#include "pr/NearestNeighborClassifier.h"
#include "util/Utility.h"
#include "util/Rank.h"

namespace pr {

NearestNeighborClassifier::NearestNeighborClassifier(std::size_t numClasses, std::size_t numFeatures, unsigned int k)
  : numClasses_(numClasses), numFeatures_(numFeatures), parameterK_(k)
{
}

void NearestNeighborClassifier::train(const Pattern& trainingPattern, std::size_t classId)
{
  trainingPatterns_.push_back(std::make_pair(trainingPattern, classId));
}

std::size_t NearestNeighborClassifier::classify(const Pattern& testPattern)
{
  std::vector<std::size_t> cl(parameterK_);
  Pattern dist(parameterK_);

  std::size_t j = 0;
  for ( ; j < parameterK_; ++j)
  {
    dist[j] = trainingPatterns_[j].first.euclideanDistance(testPattern);
    cl[j] = trainingPatterns_[j].second;
  }

  util::Real max;
  std::size_t maxp;
  dist.maxpos(max,maxp);
  util::Real temp;
  for ( ; j < trainingPatterns_.size(); ++j)
  {
    if ((temp=trainingPatterns_[j].first.euclideanDistance(testPattern)) < max)
    {
      dist[maxp] = temp;
      cl[maxp] = trainingPatterns_[j].second;
      dist.maxpos(max,maxp);
    }
  }
  
  return *util::Utility::mostPresentValue(cl.begin(), cl.end());
}

bool NearestNeighborClassifier::test(const Pattern& testPattern, std::size_t classId)
{
  return classify(testPattern) == classId;
}

bool NearestNeighborClassifier::rank(const Pattern& testPattern, std::size_t classId, std::size_t rank)
{
  if (rank >= numClasses_)
    return true;

  util::Rank r(numClasses_, rank);

  for (std::size_t j = 0; j<trainingPatterns_.size(); ++j)
    r.addElement(trainingPatterns_[j].second, trainingPatterns_[j].first.euclideanDistance(testPattern));

  return r.result(classId);
}

//-------------------------------
//unsigned int knn::nn(pvector& pv)
//{
//  util::Real  dist, temp;
//  unsigned int  h, n=0;
//
//  dist = trainingset->tsvec(0).euclideandist(pv);
//  for (h=1; h<trainingset->length(); h++)
//    if ((temp=trainingset->tsvec(h).euclideandist(pv)) < dist)
//    {
//      dist = temp;
//      n = h;
//    }
//
//  return n;
//}
//-------------------------------
//void knn::distvector(pvector& pv, pvector& dist)
//{
//  unsigned int  h;
//
//  for (h=0; h<trainingset->length(); h++)
//    dist[h] = trainingset->tsvec(h).euclideandist(pv);
//}
//-------------------------------
//// Distance from Nearest Neighbor
//util::Real knn::dfnn(pvector& pv)
//{
//  util::Real  dist, temp;
//  unsigned int h;
//
//  dist = trainingset->tsvec(0).euclideandist(pv);
//  for (h=1; h<trainingset->length(); h++)
//    if ((temp=trainingset->tsvec(h).euclideandist(pv)) < dist)
//      dist = temp;
//
//  return dist;
//}

} // namespace pr
